/****************************************************************************
 *
 *   Copyright (c) 2012-2015 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#ifndef _uORBDevices_posix_hpp_
#define _uORBDevices_posix_hpp_

#include <stdint.h>
#include "uORBCommon.hpp"


namespace uORB
{
   class DeviceNode;
   class DeviceMaster;
}

class uORB::DeviceNode : public device::VDev
{
public:
  DeviceNode(const struct orb_metadata *meta, const char *name, const char *path, int priority);
  ~DeviceNode();

  virtual int   open(device::file_t *filp);
  virtual int   close(device::file_t *filp);
  virtual ssize_t   read(device::file_t *filp, char *buffer, size_t buflen);
  virtual ssize_t   write(device::file_t *filp, const char *buffer, size_t buflen);
  virtual int   ioctl(device::file_t *filp, int cmd, unsigned long arg);

  static ssize_t    publish(const orb_metadata *meta, orb_advert_t handle, const void *data);

protected:
  virtual pollevent_t poll_state(device::file_t *filp);
  virtual void    poll_notify_one(px4_pollfd_struct_t *fds, pollevent_t events);

private:
  struct SubscriberData {
    unsigned  generation; /**< last generation the subscriber has seen */
    unsigned  update_interval; /**< if nonzero minimum interval between updates */
    struct hrt_call update_call;  /**< deferred wakeup call if update_period is nonzero */
    void    *poll_priv; /**< saved copy of fds->f_priv while poll is active */
    bool    update_reported; /**< true if we have reported the update via poll/check */
    int   priority; /**< priority of publisher */
  };

  const struct orb_metadata *_meta; /**< object metadata information */
  uint8_t     *_data;   /**< allocated object buffer */
  hrt_abstime   _last_update; /**< time the object was last updated */
  volatile unsigned   _generation;  /**< object generation count */
  pid_t     _publisher; /**< if nonzero, current publisher */
  const int   _priority;  /**< priority of topic */

  SubscriberData    *filp_to_sd(device::file_t *filp);

  /**
   * Perform a deferred update for a rate-limited subscriber.
   */
  void      update_deferred();

  /**
   * Bridge from hrt_call to update_deferred
   *
   * void *arg    ORBDevNode pointer for which the deferred update is performed.
   */
  static void   update_deferred_trampoline(void *arg);

  /**
   * Check whether a topic appears updated to a subscriber.
   *
   * @param sd    The subscriber for whom to check.
   * @return    True if the topic should appear updated to the subscriber
   */
  bool      appears_updated(SubscriberData *sd);
};

/**
 * Master control device for ObjDev.
 *
 * Used primarily to create new objects via the ORBIOCCREATE
 * ioctl.
 */
class uORB::DeviceMaster : public device::VDev
{
public:
  DeviceMaster(Flavor f);
  ~DeviceMaster();

  virtual int   ioctl(device::file_t *filp, int cmd, unsigned long arg);
private:
  Flavor      _flavor;
};

#endif /* _uORBDeviceNode_posix.hpp */
